﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using OrbitOne.Elmah.Logic;

namespace OrbitOne.Elmah.Presenter
{
    public class ErrorSearch : UserControl
    {
        #region Controls
        protected DropDownList TimeFrames;
        protected DropDownList ResultViews;
        protected TextBox Keyword;
        protected ImageCheckBoxList ErrorLevels;
        protected ImageCheckBoxList ErrorTypes;
        protected ImageCheckBoxList UserTypes;
        protected RequiredFieldValidatorForCheckBoxLists ErrorLevelsValidator;
        protected RequiredFieldValidatorForCheckBoxLists ErrorTypesValidator;
        protected RequiredFieldValidatorForCheckBoxLists UserTypesValidator;
        protected Button Search;
        protected NiceCheckBoxList Applications;
        protected Repeater Errors;
        protected GroupedView Results;
        #endregion

        #region Member Variables
        private ErrorSearchFilter _searchFilter;
        #endregion

        #region Properties
        protected SearchRecordCollection SearchResults { get; private set; }
        protected ErrorSearchFilter SearchFilter
        {
            get
            {
                if (_searchFilter == null)
                {
                    _searchFilter = new ErrorSearchFilter();
                }
                return _searchFilter;
            }
            set { _searchFilter = value; }
        }
        #endregion

        #region Overridden methods
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Keyword.Attributes.Add("onkeydown", string.Format("if ((event.which && event.which == 13) ||(event.keyCode && event.keyCode == 13)){{document.getElementById('{0}').click();return false;}} else return true;", Search.ClientID));
            if (!Page.IsPostBack)
            {
                SetSearchResults();
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (!Page.IsPostBack)
            {
                CreateSearchFilterFromQueryString();
                MapSavedSearchFilterToUI();
                MapFilterToUI();
            }
        }

        protected void Search_Click(object sender, EventArgs e)
        {
            var groupBase = Context.Profile.GetProfileGroup("SearchFilters");
            groupBase.SetPropertyValue("DefaultSearchFilter", SearchFilter);

            if (!Page.IsValid)
            {
                SearchFilter = new ErrorSearchFilter();
                SetSearchResults();
            }
            else
            {
                MapUIToFilter();
                SetSearchResults();
            }
        }
        #endregion

        protected void SaveFilter_Click(object sender, EventArgs e)
        {
            MapUIToFilter();
            Utility.SaveSearchFilter(Context, "DefaultSearchFilter", SearchFilter);
            Button button = sender as Button;
            SearchFilter.Name = (FindControl("tbSearchFilterName" + button.CommandArgument) as TextBox).Text;
            SearchFilter.Id = int.Parse(button.CommandArgument);
            Utility.SaveSearchFilter(Context, string.Format("SearchFilter{0}", SearchFilter.Id), SearchFilter);
            ScriptManager.RegisterStartupScript(Page, GetType(), "SaveFilterOk", @"alert(""Search filter is saved!"");", true);
            SetSearchResults();
        }

        #region Build UserInterface
        private void SetSearchResults()
        {
            Results.SearchFilter = SearchFilter;
            Results.Refresh();
        }
        private void MapFilterToUI()
        {
            InitializeApplications();
            InitializeTimeFrames();
            Keyword.Text = SearchFilter.Keyword;
            InitializeResultViews();
            InitializeErrorLevels();
            InitializeErrorTypes();
            InitializeUserTypes();
        }
        private void MapUIToFilter()
        {
            SearchFilter = new ErrorSearchFilter(
                             Applications.SelectedValues,
                             TimeFrames.SelectedValue.ParseEnum<ErrorSearchFilter.TimeFrameEnum>(),
                             Keyword.Text,
                             ErrorTypes.CombinedEnumValues<ErrorSearchFilter.ErrorTypeEnum>(),
                             ErrorLevels.CombinedEnumValues<ErrorSearchFilter.ErrorLevelEnum>(),
                             UserTypes.CombinedEnumValues<ErrorSearchFilter.UserTypeEnum>(),
                             ResultViews.SelectedValue.ParseEnum<ErrorSearchFilter.ResultViewGroup>());
        }
        private void MapSavedSearchFilterToUI()
        {
            var groupBase = Context.Profile.GetProfileGroup("SearchFilters");
            for (var i = 1; i <= 10; i++)
            {
                (FindControl(string.Format("tbSearchFilterName{0}", i)) as TextBox).Text =
                        (groupBase[string.Format("SearchFilter{0}", i)] as ErrorSearchFilter).Name;
            }
        }
        private void InitializeApplications()
        {
            var service = new OrbitOneElmahErrorService();
            Applications.DataSource = service.GetApplicationsLastYear();
            Applications.DataBind();
            if (SearchFilter.AllApplications)
            {
                Applications.Items.Cast<ListItem>().ToList().ForEach(a => a.Selected = true);
            }
            else
            {
                SearchFilter.Applications.ToList().ForEach(a => Applications.Items.FindByText(a).Selected = true);
            }
        }
        private void InitializeErrorLevels()
        {
            AddToErrorLevels("Error Level: 0,1", ErrorSearchFilter.ErrorLevelEnum.Level1);
            AddToErrorLevels("Error Level: 2,3", ErrorSearchFilter.ErrorLevelEnum.Level2);
            AddToErrorLevels("Error Level: 4,5", ErrorSearchFilter.ErrorLevelEnum.Level3);
        }
        private void InitializeErrorTypes()
        {
            AddToErrorTypes(ErrorSearchFilter.ErrorTypeEnum.Code);
            AddToErrorTypes(ErrorSearchFilter.ErrorTypeEnum.Infrastructure);
        }
        private void InitializeUserTypes()
        {
            AddToUserTypes(ErrorSearchFilter.UserTypeEnum.Anonymous);
            AddToUserTypes(ErrorSearchFilter.UserTypeEnum.User);
            AddToUserTypes(ErrorSearchFilter.UserTypeEnum.Webbots);
            AddToUserTypes(ErrorSearchFilter.UserTypeEnum.HomeUser);
        }
        private void InitializeTimeFrames()
        {
            AddToTimeFrames("Last 12 hours", ErrorSearchFilter.TimeFrameEnum.Last12Hours);
            AddToTimeFrames("Last 24 hours", ErrorSearchFilter.TimeFrameEnum.Last24Hours);
            AddToTimeFrames("Last 48 hours", ErrorSearchFilter.TimeFrameEnum.Last48Hours);
            AddToTimeFrames("Last week", ErrorSearchFilter.TimeFrameEnum.LastWeek);
            AddToTimeFrames("Last month", ErrorSearchFilter.TimeFrameEnum.LastMonth);
            AddToTimeFrames("Last year", ErrorSearchFilter.TimeFrameEnum.LastYear);
        }
        private void InitializeResultViews()
        {
            AddToResultViews("Exception message", ErrorSearchFilter.ResultViewGroup.ExceptionMessage);
            AddToResultViews("Exception type", ErrorSearchFilter.ResultViewGroup.ExceptionType);
            AddToResultViews("Url", ErrorSearchFilter.ResultViewGroup.URL);
            AddToResultViews("List view", ErrorSearchFilter.ResultViewGroup.ListView);
        }
        private void AddToResultViews(string text, ErrorSearchFilter.ResultViewGroup resultViewGroup)
        {
            AddToList(ResultViews, text, resultViewGroup.ToString(), SearchFilter.ViewGroup == resultViewGroup);
        }
        private void AddToTimeFrames(string text, ErrorSearchFilter.TimeFrameEnum timeFrame)
        {
            AddToList(TimeFrames, text, timeFrame.ToString(), SearchFilter.TimeFrame == timeFrame);
        }
        private void AddToErrorLevels(string text, ErrorSearchFilter.ErrorLevelEnum errorLevel)
        {
            AddToList(ErrorLevels, text, errorLevel.ToString(), (SearchFilter.ErrorLevel & errorLevel) == errorLevel);
        }
        private void AddToErrorTypes(ErrorSearchFilter.ErrorTypeEnum errorType)
        {
            AddToList(ErrorTypes, errorType.ToString(), errorType.ToString(), (SearchFilter.ErrorType & errorType) == errorType);
        }
        private void AddToUserTypes(ErrorSearchFilter.UserTypeEnum userType)
        {
            AddToList(UserTypes, userType.ToString(), userType.ToString(), (SearchFilter.UserType & userType) == userType);
        }
        private void AddToList(ListControl control, string text, string value, bool selected)
        {
            control.Items.Add(new ListItem(text, value) { Selected = selected });
        }
        private void CreateSearchFilterFromQueryString()
        {
            int searchFilterSequentialId;
            if (!string.IsNullOrEmpty(Request.QueryString["fsid"]) && int.TryParse(Request.QueryString["fsid"], out searchFilterSequentialId))
            {
                var filter = Utility.GetSearchFilter(Context, string.Format("SearchFilter{0}", searchFilterSequentialId));
                if (filter.Applications.Count == 0)
                    filter.AllApplications = true;
                Utility.SaveSearchFilter(Context, "DefaultSearchFilter", filter);
                SearchFilter = filter;
                return;
            }
            var queryStringExist = false;
            var allApplication = false;
            var application = string.Empty;
            var timeFrame = ErrorSearchFilter.TimeFrameEnum.LastWeek;
            var viewGroup = ErrorSearchFilter.ResultViewGroup.ExceptionMessage;
            var keyword = string.Empty;
            var errorLevel = ErrorSearchFilter.ErrorLevelEnum.All;
            var errorType = ErrorSearchFilter.ErrorTypeEnum.All;
            var userType = ErrorSearchFilter.UserTypeEnum.All;

            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_ALL_APPLICATION].IsNotNullOrEmpty())
            {
                if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_ALL_APPLICATION].ToLower() == "true")
                {
                    allApplication = true;
                    queryStringExist = true;
                }
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_APPLICATION].IsNotNullOrEmpty())
            {
                application = Request.QueryString[ErrorSearchFilter.QUERY_STRING_APPLICATION];
                queryStringExist = true;
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_TIME_FRAME].IsNotNullOrEmpty())
            {
                int iTimeFrame;
                if (int.TryParse(Request.QueryString[ErrorSearchFilter.QUERY_STRING_TIME_FRAME], out iTimeFrame))
                {
                    timeFrame = (ErrorSearchFilter.TimeFrameEnum)Enum.ToObject(typeof(ErrorSearchFilter.TimeFrameEnum), iTimeFrame);
                    queryStringExist = true;
                }
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_GROUP_VIEW].IsNotNullOrEmpty())
            {
                int iViewGroup;
                if (int.TryParse(Request.QueryString[ErrorSearchFilter.QUERY_STRING_GROUP_VIEW], out iViewGroup))
                {
                    viewGroup = iViewGroup.EnumToObject<ErrorSearchFilter.ResultViewGroup>();
                    queryStringExist = true;
                }
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_KEYWORD].IsNotNullOrEmpty())
            {
                keyword = Request.QueryString[ErrorSearchFilter.QUERY_STRING_KEYWORD];
                queryStringExist = true;
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_ERROR_LEVEL].IsNotNullOrEmpty())
            {
                int iErrorLevel;
                if (int.TryParse(Request.QueryString[ErrorSearchFilter.QUERY_STRING_ERROR_LEVEL], out iErrorLevel))
                {
                    errorLevel = iErrorLevel.EnumToObject<ErrorSearchFilter.ErrorLevelEnum>();
                    queryStringExist = true;
                }
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_ERROR_TYPE].IsNotNullOrEmpty())
            {
                int iErrorType;
                if (int.TryParse(Request.QueryString[ErrorSearchFilter.QUERY_STRING_ERROR_TYPE], out iErrorType))
                {
                    errorType = iErrorType.EnumToObject<ErrorSearchFilter.ErrorTypeEnum>();
                    queryStringExist = true;
                }
            }
            if (Request.QueryString[ErrorSearchFilter.QUERY_STRING_USER_TYPE].IsNotNullOrEmpty())
            {
                int iUserType;
                if (int.TryParse(Request.QueryString[ErrorSearchFilter.QUERY_STRING_USER_TYPE], out iUserType))
                {
                    userType = iUserType.EnumToObject<ErrorSearchFilter.UserTypeEnum>();
                    queryStringExist = true;
                }
            }
            if (queryStringExist)
            {
                SearchFilter = new ErrorSearchFilter
                                   {
                                       AllApplications = allApplication,
                                       TimeFrame = timeFrame,
                                       ViewGroup = viewGroup,
                                       Keyword = HttpUtility.UrlDecode(keyword),
                                       ErrorLevel = errorLevel,
                                       ErrorType = errorType,
                                       UserType = userType
                                   };
                if (application.IsNotNullOrEmpty()) application.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach(SearchFilter.Applications.Add);
            }
        }
        #endregion
    }
}